#include <gtest/gtest.h>
#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <condition_variable>
#include "Redis.h"

using namespace std;

extern int StartServer(int argc, char **argv);
extern shared_ptr<Redis> redis;

condition_variable cv;
mutex mtx;

class RedisTest : public ::testing::Test
{
protected:
  static thread th1;
  static void SetUpTestSuite()
  {
    // cout<<"start redis server in a thread"<<endl;
    char *argv[] = {"./redis-server", "--port", "6379"};
    int argc = 3;
    RedisTest::th1 = thread(StartServer, argc, argv);
    unique_lock<mutex> lk(mtx);
    cv.wait(lk);
  }
  static void TearDownTestSuite()
  {

    //redis->run_flag = false;
    RedisTest::th1.join();
    // cout<<"stop redis server"<<endl;
  }
};


thread RedisTest::th1;

// 执行 Linux 命令并返回输出
std::string executeCommand(const char *cmd)
{
  std::array<char, 128> buffer;
  std::string result;
  std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
  if (!pipe)
  {
    throw std::runtime_error("popen() failed!");
  }
  while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
  {
    result += buffer.data();
  }
  return result;
}

TEST_F(RedisTest, PingTest)
{

  auto result = executeCommand("redis-cli PING");
  EXPECT_EQ(result, "PONG\n");

  result = executeCommand("redis-cli PING abc");
  EXPECT_EQ(result, "abc\n");
}
TEST_F(RedisTest, EchoTest)
{
    // 向 Redis 发送 echo 命令并期望返回相同的消息
    auto result = executeCommand("redis-cli ECHO Hello");
    EXPECT_EQ(result, "Hello\n");

    // 向 Redis 发送带有特殊字符的 echo 命令并期望返回相同的消息
    result = executeCommand("redis-cli ECHO \"Special!@#\\$%^&*()_+-={}[]:\\\";'<>?,./\\\\\"");
    EXPECT_EQ(result, "Special!@#$%^&*()_+-={}[]:\";'<>?,./\\\n");

    // 向 Redis 发送空消息并期望返回空字符串
    result = executeCommand("redis-cli ECHO \"\"");
    EXPECT_EQ(result, "\n");
}


TEST_F(RedisTest, SetAndGetTest)
{
  // 测试 SET 命令
  auto setResult = executeCommand("redis-cli SET key value");
  EXPECT_EQ(setResult, "OK\n");
  // 测试 GET 命令
  auto getResult = executeCommand("redis-cli GET key");
  EXPECT_EQ(getResult, "value\n");
  getResult = executeCommand("redis-cli GET no_key");
  EXPECT_EQ(getResult, "\n");

  // 测试 SET 命令 PX
  setResult = executeCommand("redis-cli SET key_one value_one PX 100");
  EXPECT_EQ(setResult, "OK\n");
  // 测试 GET 命令
  getResult = executeCommand("redis-cli GET key_one");
  EXPECT_EQ(getResult, "value_one\n");

  std::this_thread::sleep_for(std::chrono::milliseconds(100));
  getResult = executeCommand("redis-cli GET key_one");
  EXPECT_EQ(getResult, "\n");
}
